package translinkApp.Activities;

import java.util.Collections;

import translinkApp.Adaptors.HistoryArrayAdapter;
import translinkApp.Data.DataTypes.Date;
import translinkApp.Data.DataTypes.Time;
import translinkApp.Data.Journey.Search.JourneySearch;
import translinkApp.Data.Journey.Search.JourneySearch.TimeType;
import translinkApp.Data.Journey.Search.JourneySearch.TransportType;
import translinkApp.Data.Journey.Search.JourneySearchList;
import translinkApp.Data.ResolvedLocation.ResolvedLocation;
import translinkApp.Data.ResolvedLocation.ResolvedLocationList;
import translinkApp.Data.Utils.Functions;
import translinkApp.DialogBoxes.JourneysList.JourneysListDialog;
import translinkApp.DialogBoxes.ResolveLocation.FindLocation;
import translinkApp.DialogBoxes.ResolveLocation.MyLocation;
import translinkApp.DialogBoxes.ResolveLocation.MyLocation.LocationResult;
import translinkApp.DialogBoxes.ResolveLocation.ResolveLocationDialog;
import translinkApp.DialogBoxes.ResolveLocation.ResolveLocationDialogData;
import translinkApp.DialogBoxes.SaveJourney.SaveJourneyDialog;
import translinkApp.DialogBoxes.SaveJourney.SaveJourneyDialogData;
import translinkApp.DialogBoxes.SavedLocations.OnReturnLocationListener;
import translinkApp.DialogBoxes.SavedLocations.SavedLocationsDialog;
import translinkApp.DialogBoxes.WebsiteLinks.WebsiteLinksDialog;
import translinkApp.Utilities.DataResource;
import translinkApp.Utilities.Utils;
import translinkApp.layouts.SearchLayout;
import translinkApp.views.activity.DialogGenerator;
import translinkApp.views.activity.DialogGeneratorList;
import translinkApp.views.activity.DialogLoaderActivity;
import translinkApp.views.dialog.LachDialog;
import translinkApp.views.dialog.LachDialogArguments;
import translinkApp.views.dialog.LachDialogData;
import android.app.AlertDialog;
import android.app.DatePickerDialog;
import android.app.Dialog;
import android.app.ProgressDialog;
import android.app.TimePickerDialog;
import android.content.DialogInterface;
import android.content.DialogInterface.OnDismissListener;
import android.content.Intent;
import android.content.SharedPreferences;
import android.location.Location;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.View.OnLongClickListener;
import android.widget.DatePicker;
import android.widget.TextView;
import android.widget.TimePicker;
import android.widget.Toast;

public class TranslinkApp extends DialogLoaderActivity {

	private Time time;
	private Date date;

	private final int TIME_DIALOG_ID = 0;
	private final int DATE_DIALOG_ID = 1;

	private final int LOCATION_DIALOG_ID = 0;
	private final int SAVE_DIALOG_ID = 1;

	// Menu items
	private final int MENU_SAVE_FAV = 1;
	private final int MENU_SETTINGS = 2;
	private final int MENU_TIME_NOW = 3;
	private final int MENU_HISTORY = 4;
	private final int MENU_GO_CARD = 5;
	private final int MENU_LINKS = 6;

	final int MAX_HISTORY = 3;

	private ResolvedLocation fromLocation;
	private ResolvedLocation toLocation;
	private JourneySearch search;

	// Save object key constants
	private final String FROM_LOCATION_SAVE = "fromLocation";
	private final String TO_LOCATION_SAVE = "toLocation";
	private final String ARRIVE_TYPE_SAVE = "arriveType";
	private final String TRANSPORT_TYPE_SAVE = "transportType";
	private final String DATE_SAVE = "date";
	private final String TIME_SAVE = "time";
	private final String JOURNEY_SAVE = "journey";

	private SearchLayout layout;

	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);

		PreferenceManager.setDefaultValues(this, R.xml.menu, false);
		loadSettings();

		layout = new SearchLayout(this);

		layout.fromButtonResolve.setOnClickListener(fromResolveButtonListener);
		layout.toButtonResolve.setOnClickListener(toResolveButtonListener);

		layout.fromLabel.setOnLongClickListener(labelLongClick(layout.fromLabel, true));
		layout.fromLabel.setOnClickListener(labelClick(layout.fromLabel, true));

		layout.toLabel.setOnLongClickListener(labelLongClick(layout.toLabel, false));
		layout.toLabel.setOnClickListener(labelClick(layout.toLabel, false));

		layout.timeDisplayTextView.setOnClickListener(new View.OnClickListener() {
			public void onClick(View v) {
				CreateDialog(TIME_DIALOG_ID).show();
			}
		});

		layout.loadJourney.setOnClickListener(loadJourneyListener);
		layout.swapDestination.setOnClickListener(swapDestinationsListener);
		layout.goButton.setOnClickListener(goButtonListener);

		layout.resetButton.setOnClickListener(new View.OnClickListener() {

			public void onClick(View v) {
				resetData();
			}
		});

		checkIntents();

		// LinearLayout v = (LinearLayout) findViewById(R.id.mainView);

		// AdView adView = (AdView) findViewById(R.id.adView1);
		// AdRequest re = new AdRequest();
		// re.setTesting(true);
		// adView.loadAd(re);
		// adView.setGravity(Gravity.BOTTOM);
		// v.addView(adView);
		// AdRequest re = new AdRequest();
		// re.setTesting(true);
		// adView.loadAd(re);

		setCurrentTime();

	}

	private void checkIntents() {

		Intent i = getIntent();

		if (i.getAction().equals("widget")) {

			SharedPreferences prefs = PreferenceManager
					.getDefaultSharedPreferences(getBaseContext());
			proversion = prefs.getBoolean("proversion", false);
			proversion = true;
			if (!proversion) {
				Utils.showAlertDialog(this, "Sorry, you have not upgraded to the pro version!");
				return;
			}

			final ProgressDialog progress = ProgressDialog.show(this, "Please wait...",
					"Updating your location", true, true);

			MyLocation myLocation = new MyLocation();
			myLocation.getLocation(this, progress, new LocationResult() {
				@Override
				public void gotLocation(final Location location) {
					progress.dismiss();
					try {
						String street = Functions.getFirstStreet(TranslinkApp.this, location);
						if (street.contains("-")) {
							street = street.substring(street.indexOf("-") + 1);
						}

						FindLocation.find(TranslinkApp.this, "Verify your location", street, true,
								new OnReturnLocationListener() {

									@Override
									public void onReturnLocation(ResolvedLocation fromLocation) {
										UpdateFromLocation(fromLocation, true);
										SavedLocationsDialog.showDialog(TranslinkApp.this,
												new OnReturnLocationListener() {

													@Override
													public void onReturnLocation(
															ResolvedLocation toLocation) {
														UpdateToLocation(toLocation, true);

														runSearch();
													}
												}, "Pick your destination");
									}
								});
					} catch (Exception e) {
						try {
							Utils.showAlertDialog(TranslinkApp.this,
									"There was an error interpreting the GPS data.\n"
											+ "Make sure you are connected to the Internet.");
						} catch (Exception ex) {

						}
					}
				}
			});

		}
	}

	@Override
	protected void onRestoreInstanceState(Bundle savedInstanceState) {
		super.onRestoreInstanceState(savedInstanceState);

		fromLocation = savedInstanceState.getParcelable(FROM_LOCATION_SAVE);
		UpdateFromLocation(fromLocation, true);

		toLocation = savedInstanceState.getParcelable(TO_LOCATION_SAVE);
		UpdateToLocation(toLocation, true);

		setTimeTypeComboText(savedInstanceState.getString(ARRIVE_TYPE_SAVE));
		setTransportTypeComboText(savedInstanceState.getString(TRANSPORT_TYPE_SAVE));

		time = savedInstanceState.getParcelable(TIME_SAVE);
		date = savedInstanceState.getParcelable(DATE_SAVE);

		// display the current date
		updateDateTimeDisplay();

		recreateDialog(savedInstanceState);

	}

	@Override
	protected void onSaveInstanceState(Bundle outState) {
		super.onSaveInstanceState(outState);

		outState.putParcelable(FROM_LOCATION_SAVE, fromLocation);
		outState.putParcelable(TO_LOCATION_SAVE, toLocation);

		outState.putString(ARRIVE_TYPE_SAVE, layout.arriveType.getSelectedItem().toString());
		outState.putString(TRANSPORT_TYPE_SAVE, layout.transportType.getSelectedItem().toString());

		outState.putParcelable(TIME_SAVE, time);
		outState.putParcelable(DATE_SAVE, date);

	}

	public TranslinkApp getContextInstance() {
		return TranslinkApp.this;
	}

	OnClickListener loadJourneyListener = new OnClickListener() {

		public void onClick(View v) {

			if (DataResource.journeysList.getData().size() == 0) {

				Toast.makeText(getContextInstance(), "No journeys saved.", Toast.LENGTH_SHORT)
						.show();
				return;
			}

			final JourneysListDialog journeysLoadDialog = new JourneysListDialog(
					getContextInstance());

			AlertDialog dialog = journeysLoadDialog.create();

			dialog.setOnDismissListener(new OnDismissListener() {

				@Override
				public void onDismiss(DialogInterface dialog) {
					updateJourneySearch(journeysLoadDialog.getLocationFound());
				}
			});

			dialog.show();

		}
	};

	OnClickListener swapDestinationsListener = new OnClickListener() {

		public void onClick(View v) {
			ResolvedLocation locationTemp = fromLocation;
			UpdateFromLocation(toLocation, true);
			UpdateToLocation(locationTemp, true);
		}
	};

	OnClickListener fromResolveButtonListener = new View.OnClickListener() {

		public void onClick(View v) {
			resolveLocationDialog(true);
		}
	};

	OnClickListener toResolveButtonListener = new View.OnClickListener() {

		public void onClick(View v) {
			resolveLocationDialog(false);

		}
	};

	private void resolveLocationDialog(boolean isFromLocation) {

		showLachDialog(LOCATION_DIALOG_ID, new LachDialogArguments(isFromLocation));

	}

	@Override
	public void dialogGenerator(DialogGeneratorList list) {
		list.addDialog(new DialogGenerator() {

			@Override
			public LachDialog createDialog(LachDialogArguments args, LachDialogData data) {

				final boolean isFromLocation = (Boolean) args.getArg(0);

				final ResolveLocationDialog dialogTest = new ResolveLocationDialog(
						getContextInstance(), args, (ResolveLocationDialogData) data);

				dialogTest.setOnDismissListener(new OnDismissListener() {

					@Override
					public void onDismiss(DialogInterface dialog) {
						if (isFromLocation) {
							UpdateFromLocation(dialogTest.getResolvedLocation(), false);
							layout.fromButtonResolve.setEnabled(true);
						} else {
							UpdateToLocation(dialogTest.getResolvedLocation(), false);
							layout.toButtonResolve.setEnabled(true);
						}
					}
				});

				return dialogTest;
			}
		});

		list.addDialog(new DialogGenerator() {

			@Override
			public LachDialog createDialog(LachDialogArguments args, LachDialogData data) {

				LachDialog saveJourney = new SaveJourneyDialog(getContextInstance(),
						getJourneySearch(), args, (SaveJourneyDialogData) data);

				return saveJourney;
			}
		});

	}

	OnClickListener goButtonListener = new View.OnClickListener() {

		public void onClick(View v) {
			runSearch();
		}
	};
	private boolean proversion;

	private void runSearch() {

		if (fromLocation == null || toLocation == null) {
			Utils.showAlertDialog(getContextInstance(), "Please provide a from and to destination.");
			return;
		}

		if (!Utils.isOnline(getContextInstance())) {
			return;
		}

		loadSettings();

		// Reset the search and journey options
		search = null;

		try {

			search = getJourneySearch();

			if (search == null) {
				Utils.showAlertDialog(getContextInstance(),
						"There was a problem interpreting data.");

				return;
			}

		} catch (Exception e) {
			Utils.showAlertDialog(getContextInstance(), "Please provide from and to destination.");
		}

		if (search != null) {
			addJourneyHistory(getJourneySearch());
			Intent resultsIntent = new Intent(getContextInstance(), JourneyResultActivity.class);
			resultsIntent.putExtra(JOURNEY_SAVE, getJourneySearch());
			getContextInstance().startActivity(resultsIntent);

		}
	}

	private void addJourneyHistory(JourneySearch search) {

		if (DataResource.journeysHistoryList.getData().size() == MAX_HISTORY) {
			DataResource.journeysHistoryList.getData().remove(0);
		}

		DataResource.journeysHistoryList.getData().add(search);
		DataResource.journeysHistoryList.save(this);
	}

	private void resetData() {
		UpdateFromLocation(null, true);
		UpdateToLocation(null, true);

		layout.arriveType.setSelection(0);
		layout.transportType.setSelection(0);

		setCurrentTime();
	}

	private void setCurrentTime() {

		// get the current time
		time = new Time();

		// add a click listener to the button
		layout.dateDisplayTextView.setOnClickListener(new View.OnClickListener() {
			public void onClick(View v) {
				CreateDialog(DATE_DIALOG_ID).show();
			}
		});

		// get the current date
		date = new Date();

		// display the current date
		updateDateTimeDisplay();
	}

	private void loadSettings() {
		DataResource.savedLocations.load(new ResolvedLocationList(), this);
		DataResource.journeysList.load(new JourneySearchList(), this);
		DataResource.journeysHistoryList.load(new JourneySearchList(), this);

		// Restore preferences
		SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getBaseContext());
		proversion = prefs.getBoolean("proversion", false);
		prefs.getBoolean("onlyTranslink", false);
		prefs.getString("priorityNew", "Timeliness");
		prefs.getString("maxwalk", "1000");
		prefs.getString("walkspeed", "Normal");

	}

	private OnClickListener labelClick(final TextView textView, final boolean fromLocation) {

		return new OnClickListener() {

			@Override
			public void onClick(View v) {

				SavedLocationsDialog.showDialog(getContextInstance(),
						new OnReturnLocationListener() {

							@Override
							public void onReturnLocation(ResolvedLocation location) {
								if (fromLocation) {
									UpdateFromLocation(location, false);
								} else {
									UpdateToLocation(location, false);
								}

							}
						});
			}
		};
	}

	private OnLongClickListener labelLongClick(final TextView textView, final boolean fromLocation) {

		return new OnLongClickListener() {

			@Override
			public boolean onLongClick(View v) {

				final CharSequence[] items = { "Copy Text", "Clear Location", "Add to Favourites",
						"Cancel" };

				AlertDialog.Builder builder = new AlertDialog.Builder(getContextInstance());
				builder.setTitle("Location Menu");

				builder.setItems(items, new DialogInterface.OnClickListener() {

					public void onClick(DialogInterface dialog, int item) {

						switch (item) {
						case 0:
							Utils.setClipboardText(getContextInstance(), textView.getText());
							break;

						case 1:
							if (fromLocation) {
								getContextInstance().UpdateFromLocation(null, true);
							} else {
								getContextInstance().UpdateToLocation(null, true);
							}
							break;

						case 2:
							ResolvedLocation location = null;
							if (fromLocation) {
								location = getContextInstance().fromLocation;
							} else {
								location = getContextInstance().toLocation;
							}

							if (location != null) {
								DataResource.savedLocations.getData().add(location);
								DataResource.savedLocations.save(getContextInstance());
							}
							break;
						}

					}
				});

				AlertDialog alert = builder.create();
				alert.show();
				return false;
			}
		};
	}

	private TransportType getTransportTypeEnum() {
		String transportString = layout.transportType.getSelectedItem().toString();
		TransportType transporTypeEnum = TransportType.All;

		if (transportString.equals("Bus")) {
			transporTypeEnum = TransportType.Bus;
		} else if (transportString.equals("Train")) {
			transporTypeEnum = TransportType.Train;
		} else if (transportString.equals("Ferry")) {
			transporTypeEnum = TransportType.Ferry;
		}

		return transporTypeEnum;
	}

	private TimeType getTimeTypeEnum() {
		String leaveTypeString = layout.arriveType.getSelectedItem().toString();
		TimeType timeTypeEnum = TimeType.LeaveAfter;

		if (leaveTypeString.equals("Arrive Before")) {
			timeTypeEnum = TimeType.ArriveBefore;
		} else if (leaveTypeString.equals("First Trip")) {
			timeTypeEnum = TimeType.FirstTrip;
		} else if (leaveTypeString.equals("Last Trip")) {
			timeTypeEnum = TimeType.LastTrip;
		}

		return timeTypeEnum;
	}

	private JourneySearch getJourneySearch() {

		try {

			return new JourneySearch(fromLocation, toLocation, getTransportTypeEnum(),
					getTimeTypeEnum(), time, date);
		} catch (Exception e) {
		}
		return null;
	}

	private void UpdateFromLocation(ResolvedLocation location, boolean changeNulls) {

		if (location != null) {
			fromLocation = location;
			layout.fromLabel.setText(fromLocation.getDisplayAddress());

		} else if (changeNulls) {
			fromLocation = null;
			layout.fromLabel.setText("");
		}
	}

	private void UpdateToLocation(ResolvedLocation location, boolean changeNulls) {

		if (location != null) {
			toLocation = location;
			layout.toLabel.setText(toLocation.getDisplayAddress());
		} else if (changeNulls) {
			toLocation = null;
			layout.toLabel.setText("");
		}
	}

	/* Creates the menu items */
	public boolean onCreateOptionsMenu(Menu menu) {
		MenuItem newItem = menu.add(0, MENU_SAVE_FAV, 0, "Add to Journeys");
		newItem.setIcon(android.R.drawable.ic_menu_add);

		MenuItem menuHistory = menu.add(0, MENU_HISTORY, 0, "History");
		menuHistory.setIcon(android.R.drawable.ic_menu_recent_history);

		MenuItem changeTime = menu.add(0, MENU_TIME_NOW, 0, "Reset time");
		changeTime.setIcon(android.R.drawable.ic_menu_today);

		MenuItem settingsItem = menu.add(0, MENU_SETTINGS, 0, "Settings");
		settingsItem.setIcon(android.R.drawable.ic_menu_manage);

		MenuItem gocardItem = menu.add(0, MENU_GO_CARD, 0, "Go-Card Info");
		gocardItem.setIcon(android.R.drawable.ic_menu_info_details);

		MenuItem openLink = menu.add(0, MENU_LINKS, 0, "Links");
		openLink.setIcon(android.R.drawable.ic_menu_upload);

		return true;
	}

	public boolean onOptionsItemSelected(MenuItem item) {

		switch (item.getItemId()) {
		case MENU_SAVE_FAV:

			showLachDialog(SAVE_DIALOG_ID, new LachDialogArguments(getTimeTypeEnum(),
					getTransportTypeEnum()));
			return true;

		case MENU_HISTORY:
			showHistory();
			return true;

		case MENU_SETTINGS:

			Intent settingsIntent = new Intent(getContextInstance(), SettingsActivity.class);
			getContextInstance().startActivity(settingsIntent);
			return true;

		case MENU_TIME_NOW:
			setCurrentTime();
			return true;

		case MENU_GO_CARD:
			if (!Utils.isOnline(getContextInstance())) {
				return true;
			}

			Intent goCardInfoIntent = new Intent(getContextInstance(), GoCardInfoActivity.class);
			getContextInstance().startActivity(goCardInfoIntent);
			return true;

		case MENU_LINKS:

			WebsiteLinksDialog alerter = new WebsiteLinksDialog(this);

			AlertDialog websiteLinksDialog = alerter.create();
			websiteLinksDialog.show();
			return true;

		}
		return false;
	}

	public void showHistory() {

		final JourneySearchList newList = (JourneySearchList) DataResource.journeysHistoryList
				.getData().clone();

		if (newList.size() == 0) {
			Toast.makeText(getContextInstance(), "No history saved.", Toast.LENGTH_SHORT).show();
			return;
		}

		Collections.reverse(newList);

		AlertDialog.Builder builder = new AlertDialog.Builder(getContextInstance());
		builder.setTitle("History");

		builder.setAdapter(new HistoryArrayAdapter(this, newList),
				new DialogInterface.OnClickListener() {

					public void onClick(DialogInterface dialog, int item) {
						JourneySearch selectedSearch = newList.get(item);
						updateJourneySearch(selectedSearch);
					}

				});

		AlertDialog alert = builder.create();
		alert.show();
	}

	private void setTimeTypeComboText(String value) {
		int count = layout.arriveType.getCount();
		String arriveTypeString = value;
		for (int i = 0; i < count; i++) {
			String arriveItem = layout.arriveType.getItemAtPosition(i).toString().replace(" ", "");
			arriveTypeString = arriveTypeString.replace(" ", "");
			if (arriveItem.equals(arriveTypeString)) {

				layout.arriveType.setSelection(i, true);
				break;

			}
		}
	}

	private void setTransportTypeComboText(String value) {
		int count = layout.transportType.getCount();

		for (int i = 0; i < count; i++) {
			String arriveItem = layout.transportType.getItemAtPosition(i).toString();
			if (arriveItem.equals(value)) {

				layout.transportType.setSelection(i, true);
				break;

			}
		}
	}

	private void updateJourneySearch(JourneySearch journey) {
		if (journey != null) {
			UpdateFromLocation(journey.getFromLocation(), true);
			UpdateToLocation(journey.getToLocation(), true);

			if (journey.getTime() != null) {
				time = new Time(journey.getTime());
			}

			if (journey.getDate() != null) {
				date = new Date(journey.getDate());
			}

			if (journey.getTimeType() != null) {
				String timeType = journey.getTimeType().toString();
				setTimeTypeComboText(timeType);
			}

			if (journey.getTransport() != null) {
				setTransportTypeComboText(journey.getTransport().toString());
			}
		}

		updateDateTimeDisplay();
	}

	/**
	 * Updates the time we display in the TextViews
	 */
	private void updateDateTimeDisplay() {
		layout.timeDisplayTextView.setText(time.toString());
		layout.dateDisplayTextView.setText(date.toDisplayString());

	}

	private Dialog CreateDialog(int id) {
		switch (id) {
		case TIME_DIALOG_ID:
			TimePickerDialog timePicker = new TimePickerDialog(this, mTimeSetListener,
					time.getHour(), time.getMinute(), false);

			return timePicker;
		case DATE_DIALOG_ID:

			DatePickerDialog dialog = new DatePickerDialog(this, mDateSetListener, date.getYear(),
					date.getMonth() - 1, date.getDay());

			return dialog;

		}
		return null;
	}

	private DatePickerDialog.OnDateSetListener mDateSetListener = new DatePickerDialog.OnDateSetListener() {

		public void onDateSet(DatePicker view, int year, int monthOfYear, int dayOfMonth) {
			date = new Date(dayOfMonth, monthOfYear + 1, year);
			updateDateTimeDisplay();
		}
	};

	private TimePickerDialog.OnTimeSetListener mTimeSetListener = new TimePickerDialog.OnTimeSetListener() {
		public void onTimeSet(TimePicker view, int hourOfDay, int minute) {
			time = new Time(hourOfDay, minute);
			updateDateTimeDisplay();
		}
	};

}